package com.fc.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fc.context.BaseContext;
import com.fc.entity.LoginUser;
import com.fc.entity.User;
import com.fc.exception.LoginException;
import com.fc.mapper.UserMapper;
import com.fc.properties.JwtProperties;
import com.fc.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Component
@Slf4j
public class JwtTokenInterceptor extends OncePerRequestFilter {

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    @Qualifier("objectRedisTemplate")
    private RedisTemplate<String, Object> objectRedisTemplate;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //获取令牌
        String token = request.getHeader(jwtProperties.getTokenName());
        if (!StringUtils.hasText(token)) {
            filterChain.doFilter(request, response);
            return;
        }
        //校验令牌
        Long userId;
        try {
            log.info("jwt校验:{}", token);
            // 检查令牌是否在 Redis 黑名单中
            if (Boolean.TRUE.equals(objectRedisTemplate.hasKey(token))) {
                throw new LoginException("令牌已登出");
            }
            //token解析
            Claims claims = JwtUtil.parseJWT(jwtProperties.getSecretKey(), token);
            userId = Long.valueOf(claims.get("userId").toString());
            BaseContext.setCurrentId(userId);
            log.info("当前用户id:{}", userId);

            //查询用户信息
            User user = userMapper.selectById(userId);

            // 检查是否超过一个月未登录
            if (user.getLastLogin() != null && user.getLastLogin().isBefore(LocalDateTime.now().minusMonths(1))) {
//                extracted(response, "登录已过期，请重新登录");
                sendJsonError(response, "登录已过期，请重新登录");
                return;
            }

            List<String> roles = new ArrayList<>(userMapper.selectRolesByUserId(userId));
            LoginUser loginUser = new LoginUser(user, roles);
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            //放行
            filterChain.doFilter(request, response);
        } catch (Exception ex) {
//            extracted(response, "token非法");
            sendJsonError(response, "token非法");
        }

    }

    /*private void extracted(HttpServletResponse response, String msg) throws IOException {
        // 设置响应的内容类型和字符编码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        // 构造自定义响应体
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("code", 0);
        body.put("msg", msg);
        body.put("data", null);
        // 将响应体写入输出流
        try (OutputStream out = response.getOutputStream()) {
            objectMapper.writeValue(out, body);
            out.flush();
        }
    }*/
    // 统一的JSON错误响应方法（替代extracted方法）
    private void sendJsonError(HttpServletResponse response, String message) throws IOException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("code", 0);
        body.put("msg", message);
        body.put("data", null);

        try (OutputStream out = response.getOutputStream()) {
            objectMapper.writeValue(out, body);
            out.flush();
        }
    }
}
